from django.shortcuts import render, get_object_or_404, redirect
from django.views import generic
from django.contrib.auth import login, authenticate, logout
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.contrib import messages
from django.db.models import Q
from django.urls import reverse_lazy
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.utils import timezone
from datetime import date, timedelta
from .models import Book, Author, BookInstance, Genre, UserProfile, BorrowRecord
from .forms import CustomUserCreationForm, UserProfileForm, BookForm, AuthorForm


def index(request):
    """View function for home page of site."""

    # Generate counts of some of the main objects
    num_books = Book.objects.all().count()
    num_instances = BookInstance.objects.all().count()

    # Available books (status = 'a')
    num_instances_available = BookInstance.objects.filter(status__exact='a').count()

    # The 'all()' is implied by default.
    num_authors = Author.objects.count()

    # Number of visits to this view, as counted in the session variable.
    num_visits = request.session.get('num_visits', 0)
    request.session['num_visits'] = num_visits + 1

    context = {
        'num_books': num_books,
        'num_instances': num_instances,
        'num_instances_available': num_instances_available,
        'num_authors': num_authors,
        'num_visits': num_visits,
    }

    # Render the HTML template index.html with the data in the context variable
    return render(request, 'index.html', context=context)


class BookListView(generic.ListView):
    model = Book
    context_object_name = 'book_list'
    template_name = 'catalog/book_list.html'
    paginate_by = 10

    def get_queryset(self):
        search_query = self.request.GET.get('search')
        if search_query:
            return Book.objects.filter(
                Q(title__icontains=search_query) |
                Q(author__first_name__icontains=search_query) |
                Q(author__last_name__icontains=search_query)
            )
        return Book.objects.all()


class BookDetailView(generic.DetailView):
    model = Book
    template_name = 'catalog/book_detail.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # Get available instances of this book
        context['available_instances'] = BookInstance.objects.filter(
            book=self.object,
            status='a'
        )
        return context


class AuthorListView(generic.ListView):
    model = Author
    context_object_name = 'author_list'
    template_name = 'catalog/author_list.html'
    paginate_by = 10


class AuthorDetailView(generic.DetailView):
    model = Author
    template_name = 'catalog/author_detail.html'


def register_view(request):
    if request.user.is_authenticated:
        return redirect('index')

    if request.method == 'POST':
        form = CustomUserCreationForm(request.POST)
        if form.is_valid():
            user = form.save()

            # Create user profile
            UserProfile.objects.create(
                user=user,
                phone=form.cleaned_data.get('phone', ''),
                address=form.cleaned_data.get('address', '')
            )

            # Auto login after registration
            login(request, user)
            messages.success(request, 'Registration successful! Welcome to Local Library.')
            return redirect('index')
    else:
        form = CustomUserCreationForm()

    return render(request, 'registration/register.html', {'form': form})


def logout_view(request):
    """Custom logout view that handles both GET and POST requests"""
    logout(request)
    messages.info(request, 'You have been successfully logged out.')
    return redirect('index')


@login_required
def profile(request):
    """User profile view."""
    user_profile, created = UserProfile.objects.get_or_create(user=request.user)

    if request.method == 'POST':
        form = UserProfileForm(request.POST, instance=user_profile)
        if form.is_valid():
            form.save()
            messages.success(request, 'Profile updated successfully!')
            return redirect('profile')
    else:
        form = UserProfileForm(instance=user_profile)

    return render(request, 'catalog/profile.html', {'form': form})


@login_required
def borrow_book(request, book_instance_id):
    """Borrow a book instance."""
    book_instance = get_object_or_404(BookInstance, id=book_instance_id)

    if book_instance.status != 'a':
        messages.error(request, 'This book is not available for borrowing.')
        return redirect('book-detail', pk=book_instance.book.id)

    # Check if user has already borrowed this book
    existing_borrow = BorrowRecord.objects.filter(
        user=request.user,
        book_instance=book_instance,
        status='borrowed'
    ).exists()

    if existing_borrow:
        messages.error(request, 'You have already borrowed this book.')
        return redirect('book-detail', pk=book_instance.book.id)

    # Create borrow record
    due_date = timezone.now().date() + timedelta(days=14)  # 2 weeks loan period
    BorrowRecord.objects.create(
        user=request.user,
        book_instance=book_instance,
        due_date=due_date
    )

    # Update book instance status
    book_instance.status = 'o'
    book_instance.borrower = request.user
    book_instance.due_back = due_date
    book_instance.save()

    messages.success(request, f'Successfully borrowed "{book_instance.book.title}". Due date: {due_date}')
    return redirect('my-borrowed')


@login_required
def return_book(request, borrow_record_id):
    """Return a borrowed book."""
    borrow_record = get_object_or_404(BorrowRecord, id=borrow_record_id, user=request.user)

    if borrow_record.status == 'returned':
        messages.error(request, 'This book has already been returned.')
        return redirect('my-borrowed')

    # Update borrow record
    borrow_record.return_date = timezone.now()
    borrow_record.status = 'returned'
    borrow_record.save()

    # Update book instance
    book_instance = borrow_record.book_instance
    book_instance.status = 'a'
    book_instance.borrower = None
    book_instance.due_back = None
    book_instance.save()

    messages.success(request, f'Successfully returned "{book_instance.book.title}".')
    return redirect('my-borrowed')


class LoanedBooksByUserListView(LoginRequiredMixin, generic.ListView):
    """Generic class-based view listing books on loan to current user."""
    model = BorrowRecord
    template_name = 'catalog/bookinstance_list_borrowed_user.html'
    paginate_by = 10

    def get_queryset(self):
        return BorrowRecord.objects.filter(
            user=self.request.user,
            status__in=['borrowed', 'overdue']
        ).order_by('-borrow_date')


# Admin Views (for librarians/staff)
class LoanedBooksAllListView(PermissionRequiredMixin, generic.ListView):
    """Generic class-based view listing all books on loan. Only visible to users with can_mark_returned permission."""
    model = BorrowRecord
    permission_required = 'catalog.can_mark_returned'
    template_name = 'catalog/bookinstance_list_borrowed_all.html'
    paginate_by = 10

    def get_queryset(self):
        return BorrowRecord.objects.filter(status__in=['borrowed', 'overdue']).order_by('-borrow_date')


# Book Management Views (Admin only)
class BookCreateView(PermissionRequiredMixin, CreateView):
    model = Book
    form_class = BookForm
    template_name = 'catalog/book_form.html'
    permission_required = 'catalog.add_book'
    success_url = reverse_lazy('books')

    def form_valid(self, form):
        messages.success(self.request, 'Book created successfully!')
        return super().form_valid(form)


class BookUpdateView(PermissionRequiredMixin, UpdateView):
    model = Book
    form_class = BookForm
    template_name = 'catalog/book_form.html'
    permission_required = 'catalog.change_book'

    def form_valid(self, form):
        messages.success(self.request, 'Book updated successfully!')
        return super().form_valid(form)


class BookDeleteView(PermissionRequiredMixin, DeleteView):
    model = Book
    template_name = 'catalog/book_confirm_delete.html'
    permission_required = 'catalog.delete_book'
    success_url = reverse_lazy('books')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # Get all book instances for this book
        book_instances = self.object.bookinstance_set.all()
        context['book_instances'] = book_instances
        context['borrowed_instances'] = book_instances.filter(status='o')
        context['total_instances'] = book_instances.count()

        # Get all borrow records for this book
        borrow_records = BorrowRecord.objects.filter(
            book_instance__book=self.object
        )
        context['total_borrow_records'] = borrow_records.count()
        context['active_borrow_records'] = borrow_records.filter(status='borrowed')
        return context

    def delete(self, request, *args, **kwargs):
        self.object = self.get_object()
        book_title = self.object.title
        total_instances = self.object.bookinstance_set.count()
        borrowed_count = self.object.bookinstance_set.filter(status='o').count()

        # Get all borrow records before deletion
        all_borrow_records = BorrowRecord.objects.filter(book_instance__book=self.object)
        total_records = all_borrow_records.count()
        active_records = all_borrow_records.filter(status='borrowed').count()

        try:
            # Force return all borrowed copies before deletion
            if borrowed_count > 0:
                borrowed_instances = self.object.bookinstance_set.filter(status='o')
                for instance in borrowed_instances:
                    # Set book instance as available
                    instance.status = 'a'
                    instance.borrower = None
                    instance.due_back = None
                    instance.save()

                    # Mark corresponding borrow records as returned
                    active_borrows = BorrowRecord.objects.filter(
                        book_instance=instance,
                        status='borrowed'
                    )
                    for borrow in active_borrows:
                        borrow.status = 'returned'
                        borrow.return_date = timezone.now()
                        borrow.save()

            # Now delete the book (this will cascade delete all instances and records)
            messages.success(
                request,
                f'Book "{book_title}" has been successfully deleted along with:\n'
                f'• {total_instances} book cop{"y" if total_instances == 1 else "ies"}\n'
                f'• {total_records} borrowing record{"" if total_records == 1 else "s"}\n'
                f'• {borrowed_count} cop{"y was" if borrowed_count == 1 else "ies were"} automatically returned'
                if borrowed_count > 0 else
                f'Book "{book_title}" and all its {total_instances} cop{"y" if total_instances == 1 else "ies"} '
                f'and {total_records} related record{"" if total_records == 1 else "s"} have been deleted successfully!'
            )
            return super().delete(request, *args, **kwargs)

        except Exception as e:
            messages.error(request, f'Error deleting book: {str(e)}')
            return redirect('book-detail', pk=self.object.pk)


# Author Management Views (Admin only)
class AuthorCreateView(PermissionRequiredMixin, CreateView):
    model = Author
    form_class = AuthorForm
    template_name = 'catalog/author_form.html'
    permission_required = 'catalog.add_author'
    success_url = reverse_lazy('authors')

    def form_valid(self, form):
        messages.success(self.request, 'Author created successfully!')
        return super().form_valid(form)


class AuthorUpdateView(PermissionRequiredMixin, UpdateView):
    model = Author
    form_class = AuthorForm
    template_name = 'catalog/author_form.html'
    permission_required = 'catalog.change_author'

    def form_valid(self, form):
        messages.success(self.request, 'Author updated successfully!')
        return super().form_valid(form)


class AuthorDeleteView(PermissionRequiredMixin, DeleteView):
    model = Author
    template_name = 'catalog/author_confirm_delete.html'
    permission_required = 'catalog.delete_author'
    success_url = reverse_lazy('authors')

    def form_valid(self, form):
        messages.success(self.request, 'Author deleted successfully!')
        return super().form_valid(form)


@permission_required('catalog.can_mark_returned')
def admin_return_book(request, borrow_record_id):
    """Admin function to return a book on behalf of user."""
    borrow_record = get_object_or_404(BorrowRecord, id=borrow_record_id)

    if borrow_record.status == 'returned':
        messages.error(request, 'This book has already been returned.')
        return redirect('all-borrowed')

    # Update borrow record
    borrow_record.return_date = timezone.now()
    borrow_record.status = 'returned'
    borrow_record.save()

    # Update book instance
    book_instance = borrow_record.book_instance
    book_instance.status = 'a'
    book_instance.borrower = None
    book_instance.due_back = None
    book_instance.save()

    messages.success(request, f'Successfully returned "{book_instance.book.title}" for {borrow_record.user.username}.')
    return redirect('all-borrowed')
